﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PythonInvokerTest.Utils
{
    public class ConfigAccess
    {
        /// <summary>
        /// 目标Ini文件。
        /// </summary>
        public string IniFilepath { get; internal set; } = "config.ini";

        /// <summary>
        /// 读写文件时的编码，默认为Encoding.UTF8
        /// </summary>
        public Encoding FileEncoding { get; set; } = Encoding.UTF8;

        /// <summary>
        /// 读取所有的域名，读取时初始化，只读。
        /// </summary>
        public List<string> SectionNames { get; internal set; } = new List<string>();

        /// <summary>
        /// 数据存入的核心变量，所有的配置数据都写于此。
        /// </summary>
        protected Dictionary<string, ConfigItem> map = new Dictionary<string, ConfigItem>();

        public ConfigAccess() { }

        /// <summary>
        /// 以UTF-8格式读取配置文件内容。
        /// </summary>
        /// <param name="file">配置文件路径。</param>
        /// <returns></returns>
        public static ConfigAccess LoadFile(string file = "config.ini") => LoadFile(file, Encoding.UTF8);



        /// <summary>
        /// 从文件中读取配置信息。
        /// </summary>
        /// <param name="file">需要加载的文件</param>
        /// <returns>返回true表示加载成功，否则加载失败。</returns>
        public static ConfigAccess LoadFile(string file, Encoding encoding)
        {
            ConfigAccess ca = new ConfigAccess() { IniFilepath = file, FileEncoding = encoding };
            return ca.loadini(file, encoding) ? ca : null;
        }

        protected bool loadini(string filename, Encoding encoding)
        {
            if(!File.Exists(filename))
                return false;

            string currentSection = "Others";
            foreach (string line in File.ReadAllLines(IniFilepath, FileEncoding))
            {
                var ci = ConfigItem.Parse(line);
                if (ci == null || !ci.IsValid)
                    continue;

                if (ci.IsSectionName)
                {
                    currentSection = ci.SectionName;
                    continue;
                }

                ci.SectionName = currentSection;
                if (!map.Keys.Contains(ci.FullKey))
                {
                    map.Add(ci.FullKey, ci);
                    if (!SectionNames.Contains(currentSection))
                        SectionNames.Add(currentSection);
                }
            }
            return true;
        }

        public void Reload()
        {
            map.Clear();
            SectionNames.Clear();
            loadini(IniFilepath, FileEncoding);
        }

        /// <summary>
        /// 将所有内容保存至的文件，如果文件不存在则新建，如果已经存在 ，则覆盖。
        /// </summary>
        /// <param name="file">保存文件的路径。</param>
        /// <returns></returns>
        public void Save(string file = null, Encoding encoding = null)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string section in SectionNames)
            {
                sb.Append($"[{section}]\n");
                foreach (var kv in GetItemsBySectionName(section))
                    sb.Append($"{kv.Key}={kv.Value}\n");
            }
            File.WriteAllText(file ?? (IniFilepath ?? "config.ini"), sb.ToString(), encoding ?? FileEncoding);
        }

        /// <summary>
        /// 返回对应键值的项，key不存在则返回null。
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public ConfigItem GetItem(string key)
        {
            key = key.Contains(".") ? key : $"Others.{key}";
            return map.Keys.Contains(key) ? map[key] : null;
        }

        /// <summary>
        /// 返回对应键值的项，key不存在则返回null。
        /// </summary>
        /// <param name="section">段名。</param>
        /// <param name="key">健。</param>
        /// <returns></returns>
        public ConfigItem GetItemFull(string section, string key)
        {
            key = key.Contains(".") ? key : $"{section}.{key}";
            return map.Keys.Contains(key) ? map[key] : null;
        }



        /// <summary>
        /// 根据域名，返回相同域名的所有的ConfigItem。
        /// </summary>
        /// <param name="section">域名，默认为 Others</param>
        /// <returns></returns>
        public List<ConfigItem> GetItemsBySectionName(string section = "Others")
        {
            List<ConfigItem> items = new List<ConfigItem>();
            foreach (var item in map.Values)
            {
                if (item.SectionName == section)
                {
                    items.Add(item);
                }
            }

            return items;
        }

        /// <summary>
        /// 移除空格并将 null 转换为 ""，最终返回完全的 section.key 格式的名称
        /// </summary>
        /// <param name="section">段名。</param>
        /// <param name="key">键名。</param>
        /// <returns></returns>
        public string GetFullKey(string section, string key)
        {
            key = key == null || key.Trim().Length == 0 ? "" : key.Trim();
            section = section == null || section.Trim().Length == 0 ? "Others" : section.Trim();
            return key.Contains(".") ? key : $"{section}.{key}";
        }


        /// <summary>
        /// 根据键返回指定key的String类型的值如果不存在 则返回输入的缺省值，段为缺少的Others。
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="defaultValue">读取失败时返回的值，默认为 null。</param>
        /// <param name="section">所在的段，默认为 Others</param>
        /// <returns></returns>
        public string GetValue(string key, string defaultValue = "")
        {
            return GetValueFull("Others", key, defaultValue);
        }

        /// <summary>
        /// 根据段和键返回指定key的String类型的值，如果不存在 则返回输入的缺省值。
        /// </summary>
        /// <param name="section">段名。</param>
        /// <param name="key">键名。</param>
        /// <param name="defaultValue">缺省值。</param>
        /// <returns></returns>
        public string GetValueFull(string section, string key, string defaultValue = "")
        {
            string Key = GetFullKey(section, key);
            return map.Keys.Contains(Key) ? map[Key].Value : defaultValue;
        }

        /// <summary>
        /// 向指定的key值写入指定值。如果key不存在会创建，否则会进行更新。
        /// </summary>
        /// <param name="key">Key</param>
        /// <param name="value">待写入的值。</param>
        public void SetValue(string key, object value)
        {
            SetValue("Others", key, value);
        }

        /// <summary>
        /// 向指定的key值写入指定值。如果key不存在会创建，否则会进行更新。
        /// </summary>
        /// <param name="key">Key</param>
        /// <param name="objValue">待写入的值。</param>
        public void SetValue(string section, string key, object objValue)
        {
            if (objValue != null)
            {
                string Key = GetFullKey(section, key);
                string value = objValue.ToString();
                if (map.Keys.Contains(Key))
                    map[Key].Value = value;
                else
                {
                    ConfigItem item = new ConfigItem(Key, value);
                    if (!SectionNames.Contains(item.SectionName))
                        SectionNames.Add(item.SectionName);
                    map.Add(Key, item);
                }
            }
        }

    }




}
